from .fieldparse import *
from .preparse import *
from .modelparse import *

numpy_idx = {
    # array creation
    'numpy.array()': 'numpy.ndarray',
    'numpy.asarray()': 'numpy.ndarray',
   
    'numpy.zeros()': 'numpy.ndarray',
    'numpy.ones()': 'numpy.ndarray',
    'numpy.eye()': 'numpy.ndarray',
    'numpy.diag()': 'numpy.ndarray',
    
    'numpy.arange()': 'numpy.ndarray',
    
    'numpy.linspace()': 'numpy.ndarray',
    'numpy.meshgrid()': 'numpy.ndarray',
    
    'numpy.random.randn()':' numpy.ndarray',
    'numpy.random.rand()':' numpy.ndarray',
    
    
    # operation
    'numpy.reshape()': 'numpy.ndarray',
    'numpy.ndarray.reshape()': 'numpy.ndarray',
    'numpy.ndarray.T': 'numpy.ndarray',
    'numpy.ndarray[]': 'numpy.ndarray',
    'numpy.ndarray.transpose()': 'numpy.ndarray',
    'numpy.ndarray.ravel()': 'numpy.ndarray',
    
    'numpy.concatenate()': 'numpy.ndarray',
    'numpy.ndarray.dot()': 'numpy.ndarray',
    'numpy.dot()': 'numpy.ndarray',
    
    
    # math
    'numpy.sin()': 'numpy.ndarray',
    'numpy.cos()': 'numpy.ndarray',
    'numpy.tan()': 'numpy.ndarray',
    'numpy.arcsin()': 'numpy.ndarray',
    'numpy.arccos()': 'numpy.ndarray',
    'numpy.arctan()': 'numpy.ndarray',
    
    'numpy.exp()': 'numpy.ndarray',
    'numpy.log()': 'numpy.ndarray',
    'numpy.log10()': 'numpy.ndarray',
    
    'numpy.floor()': 'numpy.ndarray',
    'numpy.ceil()': 'numpy.ndarray',
    
    'numpy.prod()': 'numpy.ndarray',
    
    'numpy.sum()': 'numpy.ndarray',
    'numpy.ndarray.sum()': 'numpy.ndarray',

    'numpy.mean()': 'numpy.ndarray',
    'numpy.ndarray.mean()': 'numpy.ndarray',
    
    'numpy.max()': 'numpy.ndarray',
    'numpy.ndarray.max()': 'numpy.ndarray',
    
    'numpy.min()': 'numpy.ndarray',
    'numpy.ndarray.min()': 'numpy.ndarray',
    
    'numpy.clip()': 'numpy.ndarray',
    'numpy.sqrt()': 'numpy.ndarray',

    'numpy.linalg.norm()':'numpy.ndarray',
}

class Laxer:
    sitepkg = {}

    def __init__(self, cont=None):
        self.cont = ''
        self.objs = {
            'str': dir(str),
            'list': dir(list),
            'dict': dir(dict),
        }

        self.funcs = {'str()': 'str'}
        self.funcs.update(numpy_idx)

        self.docs = {}
        self.stack = [('root', -1)]
        self.layer = []
        self.indent = []
        self.buildin = {'str':dir(str), 'list':dir(list), 
            'dict':dir(dict), 'int':[], 'float':[]}
        self.mark = [] # 0:blank, 1:normal, 2:tab, 3:back, 4:unmatch
        if not cont is None: self.parse(cont)

    def input(self, line):
        # 空行
        if len(line)==0: 
            return self.mark.append('blank')
        sep = nsep(line)

        # 分号拆分输入
        if ';' in line:
            size = len(self.mark)
            for i in line.split(';'):
                self.input(' '*sep + i.strip())
            self.mark[size] = self.mark[-1]
            del self.mark[size+1:]
            return
        
        # 弹出子元素
        while sep<=self.stack[-1][1]:
            self.stack.pop()

        # import 解析
        if 'import ' in line:
            ims = parse_import(line)
            path, lay = self.stack[-1]
            for model, func, name in ims:
                key = model + ('.' + func if func!='' else '')
                if not key in self.objs:
                    _, fields, cls = import_model(model, func, name)
                    if _ is None: return
                    print('new import', model)
                    self.objs[key] = fields
                    for c in cls:
                        self.funcs[c+'()'] = c
                        self.objs[c] = cls[c]
                self.contex[path+'.'+name] = ('var', key)

        # 类解析
        if line.strip().startswith('class '):
            self.mark.append('class')
            path, lay = self.stack[-1]
            name, base = parse_class(line)
            self.stack.append((path+'.'+name, sep))
            self.contex[path+'.'+name] = ('class', base)
            #self.contex[path+'.'+name+'()'] = (
            #    'func', path+'.'+name)
            
        # 函数解析
        elif line.strip().startswith('def '):
            self.mark.append('def')
            path, lay = self.stack[-1]
            name, ps = parse_function(line)
            if name is None: return self.mark.append('e:f')
            self.stack.append((path+'.'+name, sep))
            self.contex[path+'.'+name] = ('func', None)
            for i in ps:
                self.contex[path+'.'+name+'.'+i] = ('var', None)
                
        # 表达式解析
        elif '=' in line:
            self.mark.append('normal')
            vs, ts = parse_field(line)
            path = self.stack[-1][0]
            for i, j in zip(vs, ts):
                # if '[' in i: continue
                name = self.abs_path(path, i, True)
                self.contex[name] = self.eval_expr(path, j)
        else: self.mark.append('normal')
        
    def eval_expr(self, path, expr):
        # print(path, expr, 'self eval path')
        return eval_expr(path, expr, self.contex, self.objs, self.funcs)
    
    def abs_path(self, path, word='', new=False):
        return abs_path(path, word, self.contex, self.objs, self.funcs, new)

    def abs_type(self, expr):
        return abs_type(expr, self.contex, self.objs, self.funcs)
    
    def list(self, num, word):
        #print('===================================')
        nword = rm_para(rm_num(rm_bracket(rm_bracket([word]))))[0]
        tp = self.eval_expr(self.layer[num], nword)
        if tp[1] in self.contex:
            ls = self.contex.keys()
            ls = [i for i in ls if i.startswith(tp[1]+'.')]
            ls = [i[len(tp[1])+1:] for i in ls]
            ls = [i.split('.')[0] for i in ls if i!='']
            return sorted(set(ls))
        return self.objs.get(tp[1], [])
        
    def doc(self, num, word):
        path = self.layer[num]
        for i in word.split('.'):
            path = self.abs_path(path, i)
            path = self.abs_type(path)
        if path in self.docs: return self.docs[path]
        path = self.layer[num]
        for i in word.split('.')[:-1]:
            path = self.abs_path(path, i)
            path = self.abs_type(path)
        if path in self.contex: 
            tp, name = self.contex[path]
            if tp=='model' and word.split('.')[-1] in dir(self.sitepkg[name]):
                return eval('self.sitepkg[name].%s.__doc__'%word.split('.')[-1])
        return ''

    def tab(self, num):
        # print(self.cont[num], num, 'tab')
        '''
        if self.cont[num].strip()[-1:]!=':': 
            return self.indent[num]
        else: 
            return self.indent[num] + 4
        '''
        if self.mark[num]=='(]' and (num==0 or self.mark[num-1]!='(]'):
            if '(' in self.cont[num]: 
                return self.cont[num].index('(') +1
            else: return self.indent[num]+4
        if self.cont[num].strip()[-1:]==':': 
            for n in range(num, -1, -1):
                if n==0 or self.mark[n-1]!='(]':
                    return self.indent[n] + 4
        return self.indent[num]
    
    def parse(self, cont):
        self.cont = cont.split('\n')
        self.cont = rm_common(self.cont)
        self.cont = rm_bracket(self.cont)
        self.cont = rm_num(self.cont)
        self.cont = rm_para(self.cont)
        
        self.contex = {'root': ('file', 'main')}
        for line in self.cont:
            self.input(line)
            self.layer.append(self.stack[-1][0])
            self.indent.append(nsep(line))
        # self.input('')
        
    def printf(self):
        for i in sorted(self.contex.keys()):
            print(i, self.contex[i])

    def print_doc(self):
        for i in self.docs:
            # print(i, '>>>')
            print(self.docs[i])

    def print_line(self):
        for i, s, l, c in zip(self.indent, self.mark, self.layer, self.cont):
            print('%2s'%i, '%-10s'%s, '%-30s'%l, '|', c)

if __name__ == '__main__':
    #cont = 'a = b, (c, d) = np.zeros(3, dtype=np.uint8), (2, 3)'
    cont = '''
from numpy.linalg import norm
import numpy as np

a = (np.arange(10).sum() + 100).$
    '''
    code = Laxer()
    code.parse(cont)
    print('tree >>>')
    code.printf()


